﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace Factory
{
    #region 装载IProdcut的容器类型
    /// <summary>
    /// 装载IProduct的容器类型
    /// </summary>
    public class ProductCollection
    {
        private IList<IProduct> _data = new List<IProduct>();

        /// <summary>
        /// 对外的集合操作方法
        /// </summary>
        /// <param name="item"></param>
        public void Insert(IProduct item) { _data.Add(item); }

        public void Insert(IProduct[] items)
        {
            if (items == null || items.Length == 0) return;
            foreach (var item in items) { _data.Add(item); }
        }
        public void Remove(IProduct item) { _data.Remove(item); }
        public void Clear() { _data.Clear(); }

        /// <summary>
        /// 获取所有IProdcut内容的属性
        /// </summary>
        public IProduct[] Data
        {
            get
            {
                if (_data == null || _data.Count == 0) return null;
                var result = new IProduct[_data.Count];
                _data.CopyTo(result, 0);
                return result;
            }
        }
        /// <summary>
        /// 获取当前集合内的元素数量
        /// </summary>
        public int Count => _data.Count;

        /// <summary>
        /// 为了便于操作，重载的运算符
        /// </summary>
        /// <param name="collection"></param>
        /// <param name="items"></param>
        /// <returns></returns>
        public static ProductCollection operator +(ProductCollection collection, IProduct[] items)
        {
            var result = new ProductCollection();
            if (!(collection == null || collection.Count == 0)) result.Insert(collection.Data);
            if (!(items == null || items.Length == 0)) result.Insert(items);
            return result;
        }
        public static ProductCollection operator +(ProductCollection source, ProductCollection target)
        {
            var result = new ProductCollection();
            if (!(source == null || source.Count == 0)) result.Insert(source.Data);
            if (!(target == null || target.Count == 0)) result.Insert(target.Data);
            return result;
        }


    }
    #endregion


    #region 定义批量工厂和产品类型容器
    public interface IBatchFactory
    {
        /// <summary>
        /// 
        /// </summary>
        /// <param name="quantity">待加工的产品数量</param>
        /// <returns></returns>
        ProductCollection Create(int quantity);
    }

    /// <summary>
    /// 为了方便提供的抽象基类
    /// </summary>
    /// <typeparam name="T">Concrete Product基类</typeparam>
    public class BatchProductFactoryBase<T> : IBatchFactory where T : IProduct, new()
    {
        public virtual ProductCollection Create(int quantity)
        {
            if (quantity <= 0) throw new ArgumentException();
            var collection = new ProductCollection();
            for (var i = 0; i < quantity; i++) collection.Insert(new T());
            return collection;
        }
    }



    /// <summary>
    /// 两个实体批量生产工厂类型
    /// </summary>
    public class BatchProductAFactory : BatchProductFactoryBase<ProductA> { }

    public class BatchProductBFactory : BatchProductFactoryBase<ProductB> { }


    #endregion



    #region 增加生产指导顾问——Director

    public abstract class DecisionBase
    {
        private readonly IBatchFactory _factory;
        private readonly int _quantity;
        protected DecisionBase(IBatchFactory factory, int quantity)
        {
            _factory = factory; _quantity = quantity;
        }

        public virtual IBatchFactory Factory => _factory;
        public virtual int Quantity => _quantity;
    }

    public abstract class DirectorBase
    {
        private IList<DecisionBase> _decisions = new List<DecisionBase>();

        /// <summary>
        /// 实际项目中，最好将每个Derector需要添加的Decision也定义在配置文件中
        /// 这样增加新的Decison项都在后台完成，而不需要Assembler显示调用该方法补充
        /// </summary>
        /// <param name="decision"></param>
        protected virtual void Inset(DecisionBase decision)
        {
            if (decision == null || decision.Factory == null || decision.Quantity < 0) throw new ArgumentException();
            _decisions.Add(decision);
        }
        /// <summary>
        /// 便于客户程序使用增加的迭代器
        /// </summary>
        public virtual IEnumerable<DecisionBase> Decisions => _decisions;
    }
    #endregion
    #region 由Director指导的客户程序
    //这个示例采用硬编码方式，没有通过Assembler获取Dicrector
    internal class ProductADecision : DecisionBase
    {
        public ProductADecision() : base(new BatchProductAFactory(), 2) { }
    }

    internal class ProductBDecision : DecisionBase
    {
        public ProductBDecision() : base(new BatchProductBFactory(), 3) { }
    }

    public class ProductDirector : DirectorBase
    {
        public ProductDirector()
        {
            base.Inset(new ProductADecision());
            base.Inset(new ProductBDecision());
        }
    }
    #endregion
}
